
#include <sys/types.h>
#include <unistd.h>
#include "xsg_sp_runcfg.hpp"
#include "cmd_agent_mng.hpp"

cmd_agent_mng_ptr cmd_agent_mng::_instance;
boost::mutex cmd_agent_mng::_singletone_lock;

void remove_space(const std::string& buf, std::string& obuf);
void convt_alarm_msg_fmt(const std::string& buf, std::string& rst_buf);
int parsing_alarms(const std::string& t, string_vector& rst_vec);

cmd_agent_mng_ptr cmd_agent_mng::instance() 
{
    if (_instance.use_count() == 0) {   /* FIXME */
        boost::mutex::scoped_lock scoped_lock(_singletone_lock);
        if (_instance.use_count() == 0) {
            _instance.reset(new cmd_agent_mng());
        }
    }
    return _instance;
};

cmd_agent_mng::cmd_agent_mng()
:_func_num(0)
{
    tcp::resolver resolver(_io_service);
    tcp::resolver::query query("localhost", "8888");
    tcp_endpoint rep =  *resolver.resolve(query);

    _session.reset(new cmd_mng_session(_io_service, rep));
    PDBG("CREATE CMD_AGENT_MNG!!\n");
}

cmd_agent_mng::~cmd_agent_mng() { PDBG("DELETE CDM_AGENT_MNG \n"); }

void cmd_agent_mng::run() 
{ 
    _io_service.run(); 
};

void cmd_agent_mng::stop() 
{ 
    _session->disconnect(); 
    _io_service.stop();
};

void cmd_agent_mng::show_agent_runcfg(vty_ptr vty)
{
	xsg_sp_runcfg(vty);
}

bool cmd_agent_mng::add_mode(const std::string name, 
        const std::string prompt, bool is_auth)
{
    __u32 id, cmd, ret;
    vty_ipc_message_t msg;

    string_vector req_opts;
    if (!_session->connect()) { 
        return false; 
    }
    req_opts.push_back(name);
    req_opts.push_back(prompt);
    req_opts.push_back((is_auth == true) ? "true" : "false");

	{
		boost::mutex::scoped_lock lock(_io_lock);	/* FIXME */
		_ipcmsg.build_msg(0xFF, VTY_ADD_MODE, VTY_RET_NONE, req_opts, msg);
		if (!_session->send_msg(msg)) return false;
		if (!_session->recv_msg(msg)) return false;
	}


    req_opts.clear();
    _ipcmsg.parse_msg(msg, id, cmd, ret, req_opts);
    PDBG("RET: %d, \n", ret);
    if (ret != VTY_SUCC) return false;
    return true;
}

bool cmd_agent_mng::add_command( const std::string mode, 
    const std::string cmdfmt, const std::string help, ExcuteHandle run)
{
    __u32 id, cmd, ret; 
    vty_ipc_message_t msg;
    string_vector req_opts;

    if (!_session->connect()) { 
        return false; 
    }

    req_opts.push_back("localhost");
    req_opts.push_back("8132");
    req_opts.push_back(mode);
    req_opts.push_back(cmdfmt);
    req_opts.push_back(help);

    char buf[256];
    sprintf(buf, "0x1001");	/* FIXME */
    req_opts.push_back(std::string(buf));

    sprintf(buf, "%llX", _func_num);
    req_opts.push_back(std::string(buf));

    PDBG("func id: 0x%llX, %s\n", _func_num, buf);

    _ipcmsg.build_msg(0xFF, VTY_ADD_CMD, VTY_RET_NONE, req_opts, msg);
	{
		boost::mutex::scoped_lock lock(_io_lock);	/* FIXME */
		if (!_session->send_msg(msg)) { ret = VTY_FAIL; }
		else if (_session->recv_msg(msg)) {
			req_opts.clear();
			_ipcmsg.parse_msg(msg, id, cmd, ret, req_opts);
		} else { ret = VTY_FAIL; }
	}

    if (ret == VTY_SUCC) {
        boost::mutex::scoped_lock scoped_lock(_function_lock);
        _function_map[_func_num] = run; _func_num++;
    }   /* FIXME */

    PDBG("RET: %d, \n", ret);
    if (ret != VTY_SUCC) return false;
    return true;
}

bool cmd_agent_mng::send_alarm(const std::string data)
{
	__u32 id, cmd, ret; 
	vty_ipc_message_t msg;
	string_vector req_opts;
	string_vector rst_opts;

	if (!_session->connect()) { 
		return false; 
	}

	std::cout << data << "\n";
	parsing_alarms(data, rst_opts);

	boost::mutex::scoped_lock lock(_io_lock);	/* FIXME */
	for (int idx=0; idx < rst_opts.size(); idx++) {
		std::cout << rst_opts[idx] << "\n";
		req_opts.push_back(rst_opts[idx]);
		_ipcmsg.build_msg(0xFF, VTY_ALARM, VTY_RET_NONE, req_opts, msg);
		if (!_session->send_msg(msg)) { return false; }
		req_opts.clear();
	}
	return true;
}

bool cmd_agent_mng::set_dialog(int vty_id, DialogHandle& function)
{
    boost::mutex::scoped_lock scoped_lock(_dialog_lock);
    _dialog_map[vty_id] = function;
    return true;
}

bool cmd_agent_mng::get_dialog(int vty_id, DialogHandle& function)
{
    bool ret = false;
    dialog_map_iterator iter; 
    { 
        boost::mutex::scoped_lock scoped_lock(_dialog_lock);
        iter = _dialog_map.find(vty_id); 
        if (iter != _dialog_map.end()) {  /* FIXME: */
            function = (*iter).second;
            ret = true;
        } 
    }
    return ret;
}

bool cmd_agent_mng::get_function(__u64 function_id, ExcuteHandle& function) 
{
    bool ret = false;
    function_map_iterator iter; 
    { 
        boost::mutex::scoped_lock scoped_lock(_function_lock);
        iter = _function_map.find(function_id); 
        if (iter != _function_map.end()) {  /* FIXME: */
            function = (*iter).second;
            ret = true;
        }
    }
    return ret;
}

void remove_space(const std::string& buf, std::string& obuf)
{
	char* ptr = strdup(buf.c_str());
	char* sptr = NULL;
	size_t size=buf.length();
	for (int  idx=0; idx < buf.length(); idx++) {
		if (ptr[idx] != ' ') {
			sptr = ptr + idx;
			size -= idx;
			break;
		}
	}
	if (sptr == NULL) return;

	size_t rsp_pos = buf.rfind(' ');
	if (rsp_pos == std::string::npos) {
		obuf.assign(sptr);
		return;
	}

	for (; rsp_pos > 0; rsp_pos--) {
		if (ptr[rsp_pos] != ' ') {
			ptr[rsp_pos+1] = '\0';
			break;
		}
	}
	printf(">>> (%s)\n", sptr);
	obuf.assign(sptr);
}

void convt_alarm_msg_fmt(const std::string& buf, std::string& rst_buf)
{
	string_vector lines;
	string_vector words;
	std::string tmpstr, tmpstr2;
	char tmp[512];

	kstrtok(buf, "\n", lines);
	if (lines.empty()) return;
	if (lines.size() < 4) return;
	kstrtok(lines[0], " \t", words);
	sprintf(tmp, "$$ %s %s %s ", 
			words[1].c_str(), words[2].c_str(), words[0].c_str());
	rst_buf.append(tmp);
	words.clear();
	remove_space(lines[1], tmpstr);
	tmpstr.append(" ");
	rst_buf.append(tmpstr);
	tmpstr.clear();


	for (int idx=2; idx < lines.size() -1; idx++) {
		kstrtok(lines[idx], "=", words);
		words[1].append(" ");
		remove_space(words[0], tmpstr);
		remove_space(words[1], tmpstr2);
		sprintf(tmp, "(%s:%s) ", tmpstr.c_str(), tmpstr2.c_str());
		words.clear();
		tmpstr.clear(); tmpstr2.clear();
		rst_buf.append(tmp);
	}

	return;
};

int parsing_alarms(const std::string& t, string_vector& rst_vec)
{
	std::string de("COMPLETED");
	std::string tmp;
	string_vector opts;

	size_t spos = 0;
	size_t pos = 0; 
	while (1) {
		pos = t.find(de, spos);
		if (pos == std::string::npos) {
			break;
		}
		tmp.assign(t.substr(spos, (pos-spos)));
		opts.push_back(tmp);
		spos = pos + de.length(); 
	}

	for (int idx=0; idx < opts.size(); idx++) {
		tmp.clear();
		convt_alarm_msg_fmt(opts[idx], tmp);
		tmp.append("\r\n");
		rst_vec.push_back(tmp);
		std::cout << ">> " << tmp << "\n";
	}

	return 0;
}

